#include <myFs/bitset.h>
#include <stdexcept>
namespace myFs {
namespace basic {
//位图持久
using size_t = std::uint32_t;
Bitset::Bitset() : m_baseptr(nullptr), m_bitnum(0), m_used(0){};
Bitset::Bitset(void* baseptr, size_t bitnum) { init(baseptr, bitnum); };

void Bitset::init(void* baseptr, size_t bitnum) {
    m_baseptr = static_cast<size_t*>(baseptr);
    m_bitnum = bitnum;
    if (bitnum % 32 != 0) throw ::std::runtime_error("bitnum must be 32 * n");
    m_used = bitCountAll();
}
void Bitset::set(size_t i) {
    if (i >= m_bitnum)
        throw ::std::out_of_range("set(i), i should less than m_bitnum");
    size_t index = i / (sizeof(size_t) * 8);
    size_t offset = i % (sizeof(size_t) * 8);
    if (!at(i)) ++m_used;
    m_baseptr[index] |= (1ull << offset);
}
bool Bitset::at(size_t i) const {
    if (i >= m_bitnum)
        throw ::std::out_of_range("at(i), i should less than m_bitnum");
    size_t index = i / (sizeof(size_t) * 8);
    size_t offset = i % (sizeof(size_t) * 8);
    return m_baseptr[index] & (1ull << offset);
}
void Bitset::reset(size_t i) {
    if (i >= m_bitnum)
        throw ::std::out_of_range("reset(i), i should less than m_bitnum");
    size_t index = i / (sizeof(size_t) * 8);
    size_t offset = i % (sizeof(size_t) * 8);
    if (at(i)) --m_used;
    m_baseptr[index] &= ~(1ull << offset);  // bug,忘记了取反是~
}
size_t Bitset::size() const { return m_bitnum; }
size_t Bitset::used() const { return m_used; }
size_t Bitset::usedSync() { return m_used = bitCountAll(); }
size_t Bitset::bitCountAll() {
    uint32_t n = m_bitnum / (sizeof(size_t) * 8);
    size_t ret = 0;
    for (size_t i = 0; i < n; i++) {
        ret += bitCountOne(m_baseptr[i]);
    }
    return ret;
}

uint32_t Bitset::bitCountOne(uint32_t n) {
    if (n == 0) return 0;
    if (n == 0xffffffff) return 32;

    n = (n & 0x55555555) + ((n >> 1) & 0x55555555);
    n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
    n = (n & 0x0f0f0f0f) + ((n >> 4) & 0x0f0f0f0f);
    n = (n & 0x00ff00ff) + ((n >> 8) & 0x00ff00ff);
    n = (n & 0x0000ffff) + ((n >> 16) & 0x0000ffff);
    return n;
}

}  // namespace basic
}  // namespace myFs